package msgobj

import (
	"dev_gw/common"
	"dev_gw/device"
	mqttclient "dev_gw/mqttClient"
	"encoding/json"
	"fmt"
	"strings"
	"time"
)

type getMsgObjectPoint struct {
	Key  string `json:"key"`
	Val  any    `json:"val"`
	Time uint64 `json:"time"`
	Err  *int   `json:"err,omitempty"`
}

func (p *getMsgObjectPoint) SetValue(v any) *getMsgObjectPoint {
	p.Val = v
	p.Time = uint64(time.Now().UnixMilli())
	return p
}

func (p *getMsgObjectPoint) SetError(e int) *getMsgObjectPoint {
	p.Err = &e
	return p
}

type getMsgObjectDev struct {
	Id     *int                 `json:"id,omitempty"`
	Status string               `json:"status"`
	Points []*getMsgObjectPoint `json:"points"`
}

func (d *getMsgObjectDev) SetStatus(state string) *getMsgObjectDev {
	d.Status = state
	return d
}

type DevGetMsgObject struct {
	_mqtt   *mqttclient.MqttClient
	_device *device.Device

	Tick int    `json:"tick"`
	Time int64  `json:"time"`
	Src  string `json:"src"`

	Ack struct {
		Tick int   `json:"tick"`
		Time int64 `json:"time"`
	} `json:"ack"`

	Dev []*getMsgObjectDev `json:"dev"`

	dest string
}

func NewDevGetMsgObject(m *mqttclient.MqttClient, d *device.Device) *DevGetMsgObject {
	return &DevGetMsgObject{
		_mqtt:   m,
		_device: d,
	}
}

func (r *DevGetMsgObject) ToJson() string {
	v, err := json.Marshal(r)
	if err != nil {
		fmt.Println("json marshal error, err is ", err)
		return ""
	}

	return string(v)
}

func (d *DevGetMsgObject) Parse(topic, payload string) bool {

	result := strings.Split(topic, "/")
	if len(result) <= 4 {
		return false
	}

	d.dest = result[3]

	if (d.dest != "10000") && (d.dest != "dev_gw") {
		return false
	}

	err := json.Unmarshal([]byte(payload), d)
	if err != nil {
		fmt.Println("json unmarshal failed")
		return false
	}

	return true
}

func (d *DevGetMsgObject) Action() MsgInterface {

	for _, dev := range d.Dev {
		for _, point := range dev.Points {
			if !d._device.HasPoint(point.Key) {
				fmt.Println("can't find point, point name -->", point.Key)
				point.SetError(1)
				continue
			}

			point.SetValue(d._device.PointValue(point.Key))
		}
		dev.SetStatus("online")
	}
	return d
}

func (d *DevGetMsgObject) Reply() bool {
	topic := "v1/dev/" + d.dest + "/" + d.Src + "/point/get_ack"

	d.Ack.Tick = d.Tick
	d.Ack.Time = d.Time

	d.Src = common.ProcessName

	d._mqtt.Publish(topic, d.ToJson())

	return true
}
